package IC.Parser;

%%

%class Lexer
%public
%cup

%{          
		//Regular java code
		private StringBuffer curString = new StringBuffer();
		private boolean isComment = false;          
		private int CommentLineNumber = -1;
		private int lastMinusLine = -1;
		private int lastMinusCol = -1;          
		
		protected int RetrieveLineNumber() 
	    {             
	     	return yyline+1;             
	    }  
	    
	    protected int RetrieveColNumber() 
	    {             
	     	return yycolumn+1;             
	    }
		
		private void SetCommentStatus() 
		{          
			isComment = !isComment;                    
		}  
		
		private void SetCommentLineNumber() 
	    {             
	     	CommentLineNumber = RetrieveLineNumber() ;             
	    }		

		protected boolean RetrieveCommentStatus() 
		{          
			return isComment;                    
		} 
		
		protected int RetrieveCommentLineNumber() 
	    {             
	     	return CommentLineNumber ;             
	    }
		
		private void setLastMinus()
		{
			lastMinusLine = yyline + 1;
			lastMinusCol = RetrieveColNumber() + 1;
		}
		
		protected boolean isNegative() {
           return (RetrieveLineNumber() == lastMinusLine) && ((RetrieveColNumber()-1) == lastMinusCol);
    }
%}
  
%function next_token
%type Token
%line
%char
%scanerror LexicalError
%state QUOTE  
%state COMMENT  
%state BOLCK_COMMENT

//End-Of-File case
%eofval{          
	if (RetrieveCommentStatus())                  
		throw new LexicalError(RetrieveCommentLineNumber(),LexicalError.ErrorType.INVALID_COMMENT);          
	else                  
		return new Token(sym.EOF,RetrieveLineNumber());  
%eofval}  

//Macros

DIGIT=[0-9]  
NUMBER=[1-9]({DIGIT})*|0

UPPERCASE=[A-Z]  
LOWERCASE=[a-z]  
ALPHABET={UPPERCASE}|{LOWERCASE}|_  

ALPHA_NUMERIC={ALPHABET}|{DIGIT}  
ID={LOWERCASE}({ALPHA_NUMERIC})*  
CLASS_ID={UPPERCASE}({ALPHA_NUMERIC})*

IGNORED_SIGNS=[\n\r\t\f\b]
 
OK_IN_STRING=[\x20\x21\x23-\x5B\x5D-\x7E]  
ESC_STRING="\\\""|"\\\\"|"\\t"|"\\n"
VALID_ASCII_IN_STRING={OK_IN_STRING}|{ESC_STRING}  

INVALID_NUMBER=0({DIGIT})+  
INVALID_ID= {DIGIT}({ALPHA_NUMERIC})*  
OTHER=.|\n  

%%

//ordinary cases
<YYINITIAL>  "\"" { curString.setLength(0);curString.append(yytext()); yybegin(QUOTE); }  
<YYINITIAL> "(" { return new Token(sym.LP,RetrieveLineNumber()); }  
<YYINITIAL> ")" { return new Token(sym.RP,RetrieveLineNumber()); }  
<YYINITIAL> "=" { return new Token(sym.ASSIGN,RetrieveLineNumber()); } 
<YYINITIAL> "boolean" { return new Token(sym.BOOLEAN,RetrieveLineNumber()); }
<YYINITIAL> "break" { return new Token(sym.BREAK,RetrieveLineNumber()); }  
<YYINITIAL> "class" { return new Token(sym.CLASS,RetrieveLineNumber()); }  
<YYINITIAL> "," { return new Token(sym.COMMA,RetrieveLineNumber()); }  
<YYINITIAL> "continue" { return new Token(sym.CONTINUE,RetrieveLineNumber()); }
<YYINITIAL> "/" { return new Token(sym.DIVIDE,RetrieveLineNumber()); }  
<YYINITIAL> "." { return new Token(sym.DOT,RetrieveLineNumber()); }  
<YYINITIAL> "==" { return new Token(sym.EQUAL,RetrieveLineNumber()); }  
<YYINITIAL> "extends" { return new Token(sym.EXTENDS,RetrieveLineNumber()); }  
<YYINITIAL> "else" { return new Token(sym.ELSE,RetrieveLineNumber()); }  
<YYINITIAL> "false" { return new Token(sym.FALSE,RetrieveLineNumber()); }  
<YYINITIAL> ">" { return new Token(sym.GT,RetrieveLineNumber()); }  
<YYINITIAL> ">=" { return new Token(sym.GTE,RetrieveLineNumber()); }  
<YYINITIAL> "if" { return new Token(sym.IF,RetrieveLineNumber()); } 
<YYINITIAL> "int" { return new Token(sym.INT,RetrieveLineNumber()); }  
<YYINITIAL> "&&" { return new Token(sym.LAND,RetrieveLineNumber()); } 
<YYINITIAL> "[" { return new Token(sym.LB,RetrieveLineNumber()); }  
<YYINITIAL> "]" { return new Token(sym.RB,RetrieveLineNumber()); } 
<YYINITIAL> "{" { return new Token(sym.LCBR,RetrieveLineNumber()); }  
<YYINITIAL> "}" { return new Token(sym.RCBR,RetrieveLineNumber()); }  
<YYINITIAL> "length" { return new Token(sym.LENGTH,RetrieveLineNumber()); }  
<YYINITIAL> "new" { return new Token(sym.NEW,RetrieveLineNumber()); }  
<YYINITIAL> "!" { return new Token(sym.LNEG,RetrieveLineNumber()); } 
<YYINITIAL> "||" { return new Token(sym.LOR,RetrieveLineNumber()); }  
<YYINITIAL> "<" { return new Token(sym.LT,RetrieveLineNumber()); }  
<YYINITIAL> "<=" { return new Token(sym.LTE,RetrieveLineNumber()); }   
<YYINITIAL> "%" { return new Token(sym.MOD,RetrieveLineNumber()); }  
<YYINITIAL> "*" { return new Token(sym.MULTIPLY,RetrieveLineNumber()); }  
<YYINITIAL> "!=" { return new Token(sym.NEQUAL,RetrieveLineNumber()); }  
<YYINITIAL> "null" { return new Token(sym.NULL,RetrieveLineNumber()); }  
<YYINITIAL> "+" { return new Token(sym.PLUS,RetrieveLineNumber()); }   
<YYINITIAL> "return" { return new Token(sym.RETURN,RetrieveLineNumber()); }  
<YYINITIAL> ";" { return new Token(sym.SEMI,RetrieveLineNumber()); }  
<YYINITIAL> "static" { return new Token(sym.STATIC,RetrieveLineNumber()); }  
<YYINITIAL> "string" { return new Token(sym.STRING,RetrieveLineNumber()); }  
<YYINITIAL> "this" { return new Token(sym.THIS,RetrieveLineNumber()); }  
<YYINITIAL> "true" { return new Token(sym.TRUE,RetrieveLineNumber()); }  
<YYINITIAL> "void" { return new Token(sym.VOID,RetrieveLineNumber()); }  
<YYINITIAL> "while" { return new Token(sym.WHILE,RetrieveLineNumber()); }   

// special cases
<YYINITIAL> "-" { 
	setLastMinus();
	return new Token(sym.MINUS,RetrieveLineNumber()); 
} 

<YYINITIAL> " " {
	if(isNegative()) 
		setLastMinus();
}

<YYINITIAL> "//" { yybegin(COMMENT); }  
<COMMENT> . { }  
<COMMENT> \n { yybegin(YYINITIAL); }  

<YYINITIAL> "/*" 
{ 
	yybegin(BOLCK_COMMENT);
 	SetCommentStatus();
 	SetCommentLineNumber();  
}  
<BOLCK_COMMENT> . { }  
<BOLCK_COMMENT> \n { }  
<BOLCK_COMMENT> "*/" 
{ 
	yybegin(YYINITIAL);  
	SetCommentStatus();  
}  

<QUOTE> {
	[\"] 
	{	
		curString.append(yytext());                  
		yybegin(YYINITIAL);                  
		return new Token(sym.QUOTE, curString.toString() ,RetrieveLineNumber());  	
	}       
	{VALID_ASCII_IN_STRING}  { curString.append(yytext()); }                         
	.         			{ throw new LexicalError(RetrieveLineNumber(),LexicalError.ErrorType.INVALID_STRING) ;}         
}	
   
<YYINITIAL> {ID} { return new Token(sym.ID,yytext(),RetrieveLineNumber()); }  
<YYINITIAL> {CLASS_ID} { return new Token(sym.CLASS_ID,yytext(),RetrieveLineNumber()); }  

<YYINITIAL> {NUMBER} {
        try {
            String val = yytext();
            if (isNegative())
               val = "-"+val;
            new Integer(val);
        } catch (NumberFormatException e) {
                throw new LexicalError(RetrieveLineNumber(),LexicalError.ErrorType.INVALID_INTEGER,yytext());
        }
        return new Token(sym.INTEGER,yytext(),RetrieveLineNumber());
}

<YYINITIAL> {IGNORED_SIGNS} { }
<YYINITIAL> {INVALID_NUMBER} { throw new LexicalError(RetrieveLineNumber(),LexicalError.ErrorType.INVALID_NUMBER,yytext()); }  
<YYINITIAL> {INVALID_ID} { throw new LexicalError(RetrieveLineNumber(),LexicalError.ErrorType.INVALID_ID,yytext()); }  
<YYINITIAL> {OTHER} { throw new LexicalError(RetrieveLineNumber(),LexicalError.ErrorType.INVALID_CHAR,yytext()); }    
 

 